#include "config.h"
#ifdef WIN32
#  include <io.h>
#endif
#include "dkl_settings.h"
#include "DklHeader.h"

using namespace std;


//constructor
DklHeader::DklHeader(u_int16_t modus,const char *comment, u_int8_t sfs_length,
										 u_int8_t sf_loops, u_int32_t fcID, u_int8_t noc )
{
		cd_size = sfs_length * sf_loops * noc * sizeof(u_int32_t);

		magic_byte        = 0xda;        
//removed 20070322
//		version           = 0x1;

//new version: 20070322
//now four tdc values per event are stored in dkl file
//(before two were stored)
		version           = 0x2;         

		hdr_length        =   sizeof(magic_byte)
				                + sizeof(version)
				                + sizeof(hdr_length)
                        + sizeof(date)
                        + sizeof(ev_count)
                        + sizeof(this->modus)
                        + COMMENT_LENGTH
				                + sizeof(sfs_length)
                        + sizeof(sf_loops)
                        + sizeof(fcID)
                        + sizeof(cycle_count)
				                + sizeof(fileOK)
				                + sizeof(noc)
				                + cd_size;     

		// set date to local system time
		struct tm *lt; time_t t; time(&t); lt = localtime(&t);
		date.year         = lt->tm_year + 1900;
		date.month        = lt->tm_mon + 1;
		date.day          = lt->tm_mday;
		date.hour         = lt->tm_hour;
		date.minute       = lt->tm_min;
	  date.second       = lt->tm_sec;

		ev_count          = 0;       
		this->modus       = modus;             

		strcpy(this->comment,comment);

		this->sfs_length  = sfs_length;        
		this->sf_loops    = sf_loops;          
		this->fcID        = fcID;              
		cycle_count       = sfs_length * sf_loops;
		fileOK            = 1;
		this->noc         = noc;

		counterdata = new u_int32_t[ cd_size / sizeof(u_int32_t) ];
		for(unsigned int i=0; i< cd_size / sizeof(u_int32_t); i++)
				counterdata[i] = 0;
}

//constructor, reads data from fhandle
//fhandle must be an open file handle given by posix open()
DklHeader::DklHeader( int fhandle )
{
		counterdata = 0;
		fromFile(fhandle);
}

//reads data from fhandle
//fhandle must be an open file handle given by posix open()
void DklHeader::fromFile( int fhandle )
{
		if( (read(fhandle,&magic_byte,sizeof(magic_byte)) != sizeof(magic_byte))
		 || (read(fhandle,&version,sizeof(version)) != sizeof(version))
		 || (read(fhandle,&hdr_length,sizeof(hdr_length)) != sizeof(hdr_length))
		 || (read(fhandle,&date,sizeof(date)) != sizeof(date))
		 || (read(fhandle,&ev_count,sizeof(ev_count)) != sizeof(ev_count))
		 || (read(fhandle,&modus,sizeof(modus)) != sizeof(modus))
		 || (read(fhandle,comment,COMMENT_LENGTH) != (COMMENT_LENGTH))
		 || (read(fhandle,&sfs_length,sizeof(sfs_length)) != sizeof(sfs_length))
		 || (read(fhandle,&sf_loops,sizeof(sf_loops)) != sizeof(sf_loops))
		 || (read(fhandle,&fcID,sizeof(fcID)) != sizeof(fcID))
		 || (read(fhandle,&cycle_count,sizeof(cycle_count))!=sizeof(cycle_count))
		 || (read(fhandle,&fileOK,sizeof(fileOK)) != sizeof(fileOK))
		 || (read(fhandle,&noc,sizeof(noc)) != sizeof(noc)) )
				throw(IOError("DklHeader::fromFile()\n  error by read()\n",0));

		if(counterdata) delete counterdata;
		cd_size = sfs_length * sf_loops * noc * sizeof(u_int32_t);
		counterdata = new u_int32_t[ cd_size / sizeof(u_int32_t) ];

		if( (unsigned)read(fhandle,counterdata,cd_size) != cd_size )
				throw(IOError("DklHeader::toFile()\n  error by read()\n",0));
}

//writes data to fhandle
//fhandle must be an open file, handle given by posix open()
void DklHeader::toFile( int fhandle )
{
		if( (write(fhandle,&magic_byte,sizeof(magic_byte)) != sizeof(magic_byte))
		 || (write(fhandle,&version,sizeof(version)) != sizeof(version))
		 || (write(fhandle,&hdr_length,sizeof(hdr_length)) != sizeof(hdr_length))
		 || (write(fhandle,&date,sizeof(date)) != sizeof(date))
		 || (write(fhandle,&ev_count,sizeof(ev_count)) != sizeof(ev_count))
		 || (write(fhandle,&modus,sizeof(modus)) != sizeof(modus))
		 || (write(fhandle,comment,COMMENT_LENGTH) != (COMMENT_LENGTH))
		 || (write(fhandle,&sfs_length,sizeof(sfs_length)) != sizeof(sfs_length))
		 || (write(fhandle,&sf_loops,sizeof(sf_loops)) != sizeof(sf_loops))
		 || (write(fhandle,&fcID,sizeof(fcID)) != sizeof(fcID))
		 || (write(fhandle,&cycle_count,sizeof(cycle_count))!=sizeof(cycle_count))
		 || (write(fhandle,&fileOK,sizeof(fileOK)) != sizeof(fileOK))
		 || (write(fhandle,&noc,sizeof(noc)) != sizeof(noc))
  	 || ((unsigned)write(fhandle,counterdata,cd_size) != cd_size) 
		)
			throw(IOError("DklHeader::toFile()\n  error by write()\n",0));
		
}

//returns the value for specific counter and cycle
//cycle_no is counted from zero, relative to the first cycle in the dkl file
u_int32_t DklHeader::getCounter(u_int32_t counter_no, u_int32_t cycle_no)
{
		if( counter_no >= noc )
				throw IOError("DklHeader::getCounter():\n"
											"  invalid counter_no",counter_no);
		if( cycle_no >= cycle_count )
				throw IOError("DklHeader::getCounter():\n"
											"  invalid cycle_no",cycle_no);
		return counterdata[cycle_no*noc + counter_no];
}

//sets the value for specific counter and cycle
//cycle_no is counted from zero, relative to the first cycle in the dkl file
void DklHeader::setCounter(u_int32_t counter_no, u_int32_t cycle_no,
													 u_int32_t value)
{
		if( counter_no >= noc )
				throw IOError("DklHeader::getCounter():\n"
											"  invalid counter_no",counter_no);
		if( cycle_no >= cycle_count )
				throw IOError("DklHeader::getCounter():\n"
											"  invalid cycle_no",cycle_no);

		counterdata[cycle_no*noc + counter_no] = value;
}

const char *DklHeader::infoString()
{
    stringstream ss;

#ifdef DKL
    ss	 << "header information:\n---------------------------\n"
         << " magic_byte: 0x" << hex << (u_int16_t)magic_byte << endl
         << "    version: 0x" << (u_int16_t)version << endl
         << " hdr_length: " << dec << hdr_length << endl
#else
	ss	 << "run information:\n---------------------------\n"
#endif
         << "    version: " << SVN_REV << endl
         << "       date: " << dec
         << (int)date.year << (int)date.month
         << (int)date.day
         << "_" << (int)date.hour << (int)date.minute
         << (int)date.second << endl
         << "   ev_count: " << ev_count << endl
         << "      modus: " << hex << modus << dec << endl
         << "    comment: " << comment << endl
         << " sfs_length: " << (int)sfs_length << endl
         << "   sf_loops: " << (int)sf_loops << endl
         << "       fcID: " << fcID << endl
         << "cycle_count: " << cycle_count << endl
         << "     fileOK: " << (int)fileOK
         << " " << (fileOK?"(error)":"(ok)") << endl
#ifdef DKL
         << "        noc: " << (int)noc
#endif
         << endl << endl;

    return ss.str().c_str();
}
